/*
 * x86_64/mmu.hh - MMU-related data types and functions.
 * Copyright (C) 2007  Mikhail Vorozhtsov
 * See the LICENSE section of the README file for details.
 */

/* $Id$ */

#ifndef HEADER_X86_64_MMU_HH
#define HEADER_X86_64_MMU_HH

#include HEADER (utils,setters.hh)

START_NAMESPACE (x86_64)

struct pe_t
{
  union
    {
      struct
        {
          u64_t P : 1;
          u64_t RW : 1;
          u64_t US : 1;
          u64_t PWT : 1;
          u64_t PCD : 1;
          u64_t A : 1;
          u64_t D : 1;
          u64_t PAT : 1;
          u64_t G : 1;
          u64_t AVL : 3;
          u64_t base : 40;
          u64_t available: 11;
          u64_t NX : 1;
        };
      u64_t raw;
    };

  UTILS_RAW_ZERO (pe_t, u64_t)

  UTILS_BOOL_SETTER (pe_t, P)
  UTILS_BOOL_SETTER (pe_t, RW)
  UTILS_BOOL_SETTER (pe_t, US)
  UTILS_BOOL_SETTER (pe_t, PWT)
  UTILS_BOOL_SETTER (pe_t, PCD)
  UTILS_BOOL_SETTER (pe_t, A)
  UTILS_BOOL_SETTER (pe_t, D)
  UTILS_BOOL_SETTER (pe_t, PAT)
  UTILS_BOOL_SETTER (pe_t, G)
  UTILS_SETTER (pe_t, u64_t, AVL)
  UTILS_SETTER (pe_t, u64_t, base)
  UTILS_SETTER (pe_t, u64_t, available)
  UTILS_BOOL_SETTER (pe_t, NX)

  INLINE
  u64_t
  get_ptr () const
  {
    return (u64_t) base << 12;
  }

  INLINE
  pe_t &
  set_ptr (u64_t value)
  {
    base = value >> 12;
    return *this;
  }
};

struct pde2m_t
{
  union
    {
      struct
        {
          u64_t P : 1;
          u64_t RW : 1;
          u64_t US : 1;
          u64_t PWT : 1;
          u64_t PCD : 1;
          u64_t A : 1;
          u64_t D : 1;
          u64_t PS : 1;
          u64_t G : 1;
          u64_t AVL : 3;
          u64_t PAT : 1;
          u64_t : 8;
          u64_t base : 31;
          u64_t available: 11;
          u64_t NX : 1;
        };
      u64_t raw;
    };

  UTILS_RAW_ZERO (pde2m_t, u64_t)

  UTILS_BOOL_SETTER (pde2m_t, P)
  UTILS_BOOL_SETTER (pde2m_t, RW)
  UTILS_BOOL_SETTER (pde2m_t, US)
  UTILS_BOOL_SETTER (pde2m_t, PWT)
  UTILS_BOOL_SETTER (pde2m_t, PCD)
  UTILS_BOOL_SETTER (pde2m_t, A)
  UTILS_BOOL_SETTER (pde2m_t, D)
  UTILS_BOOL_SETTER (pde2m_t, PS)
  UTILS_BOOL_SETTER (pde2m_t, G)
  UTILS_SETTER (pde2m_t, u64_t, AVL)
  UTILS_BOOL_SETTER (pde2m_t, PAT)
  UTILS_SETTER (pde2m_t, u64_t, base)
  UTILS_SETTER (pde2m_t, u64_t, available)
  UTILS_BOOL_SETTER (pde2m_t, NX)

  INLINE
  u64_t
  get_ptr () const
  {
    return (u64_t) base << 21;
  }

  INLINE
  pde2m_t &
  set_ptr (u64_t value)
  {
    base = value >> 21;
    return *this;
  }
};

union vaddr_t
{
  struct
    {
      u64_t offset : 12;
      u64_t PT : 9;
      u64_t PD : 9;
      u64_t PDP : 9;
      u64_t PML4 : 9;
      u64_t SE : 16;
    };
  u64_t raw;

  UTILS_RAW_ZERO (vaddr_t, u64_t)
};

union vaddr2m_t
{
  struct
    {
      u64_t offset : 21;
      u64_t PD : 9;
      u64_t PDP : 9;
      u64_t PML4 : 9;
      u64_t SE : 16;
    };
  u64_t raw;

  UTILS_RAW_ZERO (vaddr2m_t, u64_t)
};

INLINE
static void
inv_tlb_entry (u64_t addr)
{
  asm volatile (
    "invlpg (%0)"
    :
    : "r"(addr)
  );
}

END_NAMESPACE

#endif /* HEADER_X86_64_MMU_HH */

